
package trim.testalgorithms;

import java.util.*;

import trim.common.*;

import trim.differentmaterials.core.*;
import trim.differentmaterials.generator.core.*;
import trim.differentmaterials.coefficients.*;
import trim.differentmaterials.generator.columns.*;

/**
 *
 * @author Podorov Alexander
 */

public class ExpRestTrimmer1 extends RestTrimmer
{
    private final int[] formats;

    private final Coefficients coefficients;    

    private Material material;

    private final List<int[]> tempPatterns;

    private int sumRest;
    private int tempRest;

    //private final Map<Material, Double> map;

    private int mRest;

    private int recd = 0;
    private int num = 0;

    public ExpRestTrimmer1(TrimCore core, Generator generator, Coefficients coefficients)
    {
        super(core, generator);

        formats = new int[formatCount];
        for (int i = 0; i < formatCount; i++)
        {
            formats[i] = formatOrder[i].getFormat().getLength();
        }        

        this.coefficients = coefficients;

        //map = core.getLeftMaterialsMap();

        tempPatterns = new ArrayList<int[]>();
    }

    /*public int[] bestPattern()
    {
        int length = material.getLength();
        int tail = length;
        int knifes = material.getKnifeCount();
        int count = 0;

        int value = 0;
        int record = 0;

        int[] items = new int[formatCount];
        int[] bestItems = new int[formatCount];

        int[] temp = new int[formatCount];
        
        for (int i = 0; i < formatCount; i++)
        {
            temp[i] = i;
        }

        boolean flag = true;
        int sorted = 1;
        while (flag)
        {
            flag = false;
            for (int i = 0; i < formatCount - sorted; i++)
            {
                if (formats[temp[i]] * formatRests[temp[i]] < formats[temp[i + 1]] * formatRests[temp[i + 1]])
                {
                    int index = temp[i];
                    temp[i] = temp[i + 1];
                    temp[i + 1] = index;

                    flag = true;
                }
            }
            sorted++;
        }

        int[] indexes = new int[formatCount];
        int dimension = 0;

        for (int i = 0; i < formatCount; i++)
        {
            if (formatRests[temp[i]] > 0)
            {
                indexes[dimension++] = temp[i];
            }
        }

        int current = 0;
        int lastFormat = 0;
        int[] list = new int[dimension];
        int last = - 1;
        boolean exit = false;

        do
        {
            for (int j = current; j < dimension; j++)
            {
                items[indexes[j]] = Math.min(tail / formats[indexes[j]], formatRests[indexes[j]]);

                if (items[indexes[j]] > 0)
                {
                    tail -= items[indexes[j]] * formats[indexes[j]];
                    value += items[indexes[j]] * formats[indexes[j]];
                    count += items[indexes[j]];

                    

                    list[++last] = j;
                }
            }
     
      if ((record < value) && (count <= knifes))
                    {
                        record = value;
                        for (int i = 0; i < dimension; i++)
                        {
                            bestItems[indexes[i]] = items[indexes[i]];
                        }
                    }

            if (record == length)
            {
                exit = true;
            }
            else
            {
                if (last >= 0)
                {
                    lastFormat = list[last];
                    if (items[indexes[lastFormat]] == 1)
                    {
                        last--;
                    }

                    items[indexes[lastFormat]]--;
                    tail += formats[indexes[lastFormat]];
                    value -= formats[indexes[lastFormat]];
                    count--;
                    current = lastFormat + 1;
                }
                else
                {
                    exit = true;
                }
            }

        }
        while (!exit);

        sumRest = length - record;

        return bestItems;
    }*/


    public void bestPattern()
    {
        int length = material.getLength();
        int tail = length;
        int knifes = material.getKnifeCount();
        int count = 0;

        int value = 0;
        int record = 0;

        int[] items = new int[formatCount];
        int[] bestItems = new int[formatCount];

        int[] temp = new int[formatCount];

        for (int i = 0; i < formatCount; i++)
        {
            temp[i] = i;
        }

        boolean flag = true;
        int sorted = 1;
        while (flag)
        {
            flag = false;
            for (int i = 0; i < formatCount - sorted; i++)
            {
                if (formats[temp[i]] * formatRests[temp[i]] < formats[temp[i + 1]] * formatRests[temp[i + 1]])
                {
                    int index = temp[i];
                    temp[i] = temp[i + 1];
                    temp[i + 1] = index;

                    flag = true;
                }
            }
            sorted++;
        }

        int[] indexes = new int[formatCount];
        int dimension = 0;

        for (int i = 0; i < formatCount; i++)
        {
            if (formatRests[temp[i]] > 0)
            {
                indexes[dimension++] = temp[i];
            }
        }

        int current = 0;
        int lastFormat = 0;
        int[] list = new int[dimension];
        int last = - 1;
        boolean exit = false;

        do
        {
            for (int j = current; j < dimension; j++)
            {
                items[indexes[j]] = Math.min(tail / formats[indexes[j]], formatRests[indexes[j]]);

                if (items[indexes[j]] > 0)
                {
                    tail -= items[indexes[j]] * formats[indexes[j]];
                    value += items[indexes[j]] * formats[indexes[j]];
                    count += items[indexes[j]];

                    

                    list[++last] = j;
                }
            }


            if ((record < value) && (count <= knifes))
                    {
                        record = value;
                        for (int i = 0; i < dimension; i++)
                        {
                            bestItems[indexes[i]] = items[indexes[i]];
                        }
                    }







            
            int val = 0;
            for (int k = 0; k < dimension; k++)
            {
                val += (formatRests[indexes[k]] - bestItems[indexes[k]]) * formats[indexes[k]];
            }



            if ((Math.ceil((double)val / length) <= mRest - 1) && (tempRest + tail <= sumRest))
            {
                mRest--;
                tempRest += tail;

                for (int k = 0; k < dimension; k++)
                {
                    formatRests[indexes[k]] -= bestItems[indexes[k]];
                }

                tempPatterns.add(bestItems);

                  System.out.println(Integer.toString(++num) + ") " + Integer.toString(++recd));

                bestPattern();
            }
            

           
                if (last >= 0)
                {
                    lastFormat = list[last];
                    if (items[indexes[lastFormat]] == 1)
                    {
                        last--;
                    }

                    items[indexes[lastFormat]]--;
                    tail += formats[indexes[lastFormat]];
                    value -= formats[indexes[lastFormat]];
                    count--;
                    current = lastFormat + 1;
                }
                else
                {
                    mRest++;
                    tempRest -= tail;

                    for (int k = 0; k < dimension; k++)
                    {
                        formatRests[indexes[k]] += bestItems[indexes[k]];
                    }


                    /*if (tempPatterns.size() == 0)
                    {
                        bestPattern();
                    }*/

                    tempPatterns.remove(tempPatterns.size() - 1);

                       System.out.println(Integer.toString(++num) + ") " + Integer.toString(--recd));

                    return;

                    //exit = true;
                }
            

        }
        while (!exit);

        //sumRest = length - record;

        
    }



    public void start() throws NoSolutionsException
    {
        setFormatRests();        

        material = materialStock[0].getMaterial();

        /*double totalTails = 0.0;
        for (int i = 0; i < formatCount; i++)
        {
            totalTails += formats[i] * formatRests[i];
        }

        int[] items = bestPattern();
        int primaryTail = material.getLength();
        for (int i = 0; i < formatCount; i++)
        {
            primaryTail -= items[i] * formats[i];
            formatRests[i] -= items[i];
        }

        int primaryMaterials = (int)Math.ceil(totalTails / material.getLength());

        int lowerBound = (int)Math.ceil((totalTails + primaryMaterials * primaryTail) / material.getLength());

        
        int upperBound;
        if (totalTails == 0.0)
        {
            upperBound = 0;
        }
        else
        {
            upperBound = 1;
        }


        while (isFormatRests())
        {
            items = bestPattern();

            for (int i = 0; i < formatCount; i++)
            {
                formatRests[i] -= items[i];
            }

            upperBound++;

            //RealPattern pattern = new RealPattern(items, 0.0, coefficients.getCoefficient(RealPattern.class), material);
            //pattern.setCount(1);
            //patterns.add(pattern);
        }
        
        int y = 0;*/


        /*int ms = 0;
        for (Material m : map.keySet())
        {
            ms += (int)Math.ceil(map.get(m).floatValue()) * m.getLength();

            int u = 1;
        }

        double msf = 0;
        for (Material m : map.keySet())
        {
            msf += map.get(m).floatValue() * m.getLength();

            int u = 1;
        }



        mRest = (int)Math.ceil(map.get(material).floatValue());
        sumRest = 0;

        for (int i = 0; i < formatCount; i++)
        {
            sumRest -= formatRests[i] * formats[i];
        }
        sumRest += mRest * material.getLength();

        tempRest = 0;*/


        bestPattern();



        for (int i = 0; i < tempPatterns.size(); i++)
        {
            RealPattern pattern = new RealPattern(tempPatterns.get(i), 0.0, coefficients.getCoefficient(RealPattern.class), material);
            pattern.setCount(1);
            patterns.add(pattern);
        }








        
        
        

        
        
        /*while (isFormatRests())
        {
            int[] items = bestPattern();

            
            for (int i = 0; i < formatCount; i++)
            {
                formatRests[i] -= items[i];
            }

            RealPattern pattern = new RealPattern(items, 0.0, coefficients.getCoefficient(RealPattern.class), material);
            pattern.setCount(1);            
            patterns.add(pattern);

            System.out.println(sumRest);
        }*/

        //System.out.println(sumRest);
                
    }
}
